package com.GPS_based_training.JSONUtils;

import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.GPS_based_training.support.*;

/**
 * 
 * @author Pietro Meloni
 * 
 * This class convert a Training in JSONObject and a JSONObject in a
 * Training if is possible.
 * 
 */
public class JSONStandardization {
	
	//string that must be used for retrieving from a JSONStandardization object
	//the number of trainingElements that are contained by the current training.
	private static final String NUMBER_OF_DETECTIONS = "number of detections";
	
	//string that identifies TrainingElements in the JSONStandardization
	private static final String ELEMENTS = "element";
	
	//indexes used for accessing and saving in the JSONArray
	//that will be used for saving every TrainingElement.
	private static final int distanceIndex = 0;
	private static final int latitudeIndex = 1;
	private static final int longitudeIndex = 2;
	private static final int speedIndex = 3;
	private static final int timeIndex = 4;
	
	//object that will be fulled with the Training
	private JSONObject standardObject ;
	
	//String that identified a index for accessing
	//these parameters into a JSONObject
	private static final String NAME ="name";
	private static final String DATE = "date";
	
	/**
	 * @author Pietro Meloni
	 * 
	 * Construction of the standard object.
	 * @param training: the object that must be standardized.
	 * 			    
	 */
	public JSONStandardization(Training training) throws JSONException {
		
		
		standardObject = new JSONObject();
		ArrayList<TrainingElement> currentTrainingElements = training.getDetections();
		
		
		try {

			//putting name and date in the JSONObject
			standardObject.put(NAME, training.getName());
			standardObject.put(DATE, training.getDate());
			
			//number of trainingElements contained in the current training
			standardObject.put(NUMBER_OF_DETECTIONS, currentTrainingElements.size());
			
			//putting trainingElements into JSONArray
			//WARNING: the attributes of the TrainingElement
			//must be putted and getted in order
			for( int i = 0; i < currentTrainingElements.size(); i++ ) {
				
				JSONArray arrayOfTrainingElements = new JSONArray();
				
				arrayOfTrainingElements.put(distanceIndex,currentTrainingElements.get(i).getDistance());
				arrayOfTrainingElements.put(latitudeIndex,currentTrainingElements.get(i).getLatitude());
				arrayOfTrainingElements.put(longitudeIndex, currentTrainingElements.get(i).getLongitude());
				arrayOfTrainingElements.put(speedIndex, currentTrainingElements.get(i).getSpeed());
				arrayOfTrainingElements.put(timeIndex, currentTrainingElements.get(i).getTime());
				
				//identifies every TrainingElement with a string "element" concatenated with
				//the index of the loop. Just for retrieving them in the correct order.
				standardObject.put(ELEMENTS + Integer.toString(i), arrayOfTrainingElements);
				
			}
			
		} catch(JSONException exception){
			
			exception.printStackTrace();
			
		}	
	}
	/**
	 * @author Pietro Meloni
	 * 
	 * Standard constructor, just used for initialisation of the standardObject.
	 */
	public JSONStandardization() {
		
		standardObject = new JSONObject();
		
	}
	
	
	/**
	 * @author Pietro Meloni
	 * 
	 * Gets the training in the JSONObject form.
	 * 
	 * @param training is the Training that will be returned as JSONObject
	 * @return the training in JSONObject form.
	 */
	public JSONObject getStandardObject (Training  training) {
		
		standardObject = new JSONObject();
		ArrayList<TrainingElement> currentTrainingElements = training.getDetections();
		
		
		try {
			
			//putting name and date in the JSONObject
			standardObject.put(NAME, training.getName());
			standardObject.put(DATE, training.getDate());
			
			//number of trainingElements contained in the current training
			standardObject.put(NUMBER_OF_DETECTIONS, currentTrainingElements.size());
			
			//putting trainingElements into JSONArray
			//WARNING: the attributes of the TrainingElement
			//must be putted and getted in order
			for( int i = 0; i < currentTrainingElements.size(); i++ ) {
				
				JSONArray arrayOfTrainingElements = new JSONArray();
				
				arrayOfTrainingElements.put(distanceIndex,currentTrainingElements.get(i).getDistance());
				arrayOfTrainingElements.put(latitudeIndex,currentTrainingElements.get(i).getLatitude());
				arrayOfTrainingElements.put(longitudeIndex, currentTrainingElements.get(i).getLongitude());
				arrayOfTrainingElements.put(speedIndex, currentTrainingElements.get(i).getSpeed());
				arrayOfTrainingElements.put(timeIndex, currentTrainingElements.get(i).getTime());
				
				//identifies every TrainingElement with a string "element" concatenated with
				//the index of the loop. Just for retrieving them in the correct order.
				standardObject.put(ELEMENTS + Integer.toString(i), arrayOfTrainingElements);
				
			}
			
		} catch(JSONException exception){
			
			exception.printStackTrace();
			
		}	
		
		return standardObject;
		
	}
	
	/**
	 * @author Pietro Meloni
	 * 
	 * Gets the training in the JSONObject form.
	 * 
	 * @return the training in the JSONObject form
	 * 
	 */
	public JSONObject getStandardObject() {
		
		return standardObject;
		
	}
	
	
	/**
	 * @author Pietro Meloni
	 * 
	 * This method convert a JSONObject into Training if it's possible
	 * 
	 * @param currentJSONObject is the object that must be converted
	 * @return the JSONObject converted into training
	 * 
	 * @throws JSONException
	 */
	public Training jsonObjectToTraining(JSONObject currentJSONObject) throws JSONException {
		
		//number of trainingElements
		int numberOfTrainingElement =  (Integer)currentJSONObject.get(NUMBER_OF_DETECTIONS);
		
		//array of TrainingElement retrieved from the JSONObject
		
		
		//the training that will contain the TrainingElements read from
		//the JSONObject
		Training trainingRead = new Training();
		
		//retrieving name and date of the training
		trainingRead.setDate(currentJSONObject.getString(DATE));
		trainingRead.setName(currentJSONObject.getString(NAME));
		
		for(int i = 0; i < numberOfTrainingElement; i++ ) {
			
			JSONArray jsonArrayOfElements = (JSONArray)currentJSONObject.get(ELEMENTS + Integer.toString(i));
			TrainingElement newElement = new TrainingElement(jsonArrayOfElements.getDouble(speedIndex) / 3.6, jsonArrayOfElements.getDouble(distanceIndex),
															jsonArrayOfElements.getDouble(timeIndex), jsonArrayOfElements.getDouble(latitudeIndex), jsonArrayOfElements.getDouble(longitudeIndex));
			trainingRead.add(newElement);
			
		}
		
		return trainingRead;
		
	}
	
	
	/**
	 * @author Pietro Meloni
	 * 
	 * This method convert a String recovered by a JSONObject into Training if it's possible
	 * 
	 * @param jsonString  is the String that must be converted
	 * @return the Training required
	 * 
	 * @throws JSONException
	 */
	public Training jsonObjectToTraining(String jsonString) throws JSONException {
	
		//JSONObject created from a String that was a JSONObject
		JSONObject currentJSONObject = new JSONObject(jsonString);
		
		//number of trainingElements
		int numberOfTrainingElement =  (Integer)currentJSONObject.get(NUMBER_OF_DETECTIONS);
		
		//array of TrainingElement retrieved from the JSONObject
		
		
		//the training that will contain the TrainingElements read from
		//the JSONObject
		Training trainingRead = new Training();
		
		//retrieving name and date of the training
		trainingRead.setDate(currentJSONObject.getString(DATE));
		trainingRead.setName(currentJSONObject.getString(NAME));
		
		for(int i = 0; i < numberOfTrainingElement; i++ ) {
			
			JSONArray jsonArrayOfElements = (JSONArray)currentJSONObject.get(ELEMENTS + Integer.toString(i));
			TrainingElement newElement = new TrainingElement(jsonArrayOfElements.getDouble(speedIndex), jsonArrayOfElements.getDouble(distanceIndex),
															jsonArrayOfElements.getDouble(timeIndex), jsonArrayOfElements.getDouble(latitudeIndex), jsonArrayOfElements.getDouble(longitudeIndex));
			trainingRead.add(newElement);
			
		}
		
		return trainingRead;
		
	}
	
	
}
